﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EntityFramework.Helper.Searcher
{
    /// <summary>
    /// Base criteria class.
    /// </summary>
    /// <typeparam name="E">The entity object type.</typeparam>
    public abstract class Criteria<E> : ICriteria<E> where E : System.Data.Objects.DataClasses.EntityObject
    {
        #region Fields

        /// <summary>
        /// Changed properties.
        /// </summary>
        private Dictionary<string, object> m_changedProperties;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the current criteria entity object.
        /// </summary>
        public E CurrentEntityObject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the criteria changed properties.
        /// </summary>
        public Dictionary<string, object> ChangedProperties
        {
            get
            {
                return m_changedProperties;
            }
        }

        #endregion

        #region Constructors

        public Criteria()
        {
            m_changedProperties = new Dictionary<string, object>();
        }

        #endregion

        #region ICriteria<E> Members

        /// <summary>
        /// Gets a criteria object to be used on the search.
        /// </summary>
        /// <returns>Criteria object.</returns>
        public E GetCritireiaObject()
        {
            // gets the entity object type.
            Type t = typeof(E);

            // gets the entity object constructor.
            ConstructorInfo constructor = t.GetConstructor(new Type[0]);

            // creates and populates the instance od the entity object.
            CurrentEntityObject = (E) constructor.Invoke(new object[0]);

            // creates the event to entity object property change.
            CurrentEntityObject.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(PropertyChanged);

            return CurrentEntityObject;
        }

        /// <summary>
        /// Property changed handler.
        /// </summary>
        /// <param name="sender">Origin event.</param>
        /// <param name="e">Event arguments.</param>
        void PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            // gets the entity object type.
            Type t = typeof(E);

            // get property from the entity object.
            PropertyInfo prop = t.GetProperty(e.PropertyName);

            // get the entity object property value,
            var value = prop.GetValue(CurrentEntityObject, new object[0]);

            // add or sets the property and the value to the collection.
            if (m_changedProperties.ContainsKey(e.PropertyName))
            {
                m_changedProperties[e.PropertyName] = value;
            }
            else
            {
                m_changedProperties.Add(e.PropertyName, value);
            }
        }

        #endregion
    }
}
